#!/usr/bin/env python
# -*- coding: ISO-8859-1 -*-
#
#      Kovan's OGBot
#      Copyright (c) 2007 by kovan 
#
#      *************************************************************************
#      *                                                                       *
#      * This program is free software; you can redistribute it and/or modify  *
#      * it under the terms of the GNU General Public License as published by  *
#      * the Free Software Foundation; either version 2 of the License, or     *
#      * (at your option) any later version.                                   *
#      *                                                                       *
#      *************************************************************************
#
import locale
import threading
import re
import os
import urllib
import types
import cPickle
import socket
import urllib2
import cookielib
import copy
import sys
import httplib
import warnings
import cookielib
import gzip
import math
from Queue import *
from time import strptime, time
time2 = time
from datetime import datetime, time
from cStringIO import *
from ClientForm import HTMLForm, ParseFile, ControlNotFoundError;
import keepalive
from CommonClasses import *
from Constants import *
from GameEntities import *


class WebAdapter(object):
    """Encapsulates the details of the communication with the ogame servers. This involves
        HTTP protocol encapsulation and HTML parsing.
    """
    class EventManager(BaseEventManager):
        def __init__(self, gui = None):
            super(WebAdapter.EventManager, self).__init__(gui)

        def connectionError(self, reason):
            self.logAndPrint("** CONNECTION ERROR: %s" % reason)
            self.dispatch("connectionError", reason)              
        def loggedIn(self, username, session):
            msg = 'Logged in with user %s.' % username
            self.logAndPrint(msg)
            msg = datetime.now().strftime("%X %x ") + msg
            self.dispatch("activityMsg", msg)            
        def activityMsg(self, msg):
            self.logAndPrint(msg)
            msg = datetime.now().strftime("%X %x ") + msg
            self.dispatch("activityMsg", msg)
        
    def __init__(self, config, checkThreadMsgsMethod, gui = None):
        self.server = ''
        self.lastFetchedUrl = ''
        self.serverCharset = ''        
        self.config = config
        self.gui = gui
        self.cookie = None
        self.checkThreadMsgsMethod = checkThreadMsgsMethod
        self._eventMgr = WebAdapter.EventManager(gui)
        self.serverTimeDelta = None
        self._mutex = threading.RLock()
        self.scanThread = None
        self.myPlanetsResources = []
        self.currentTime = 0
        
        self.webpage = self.config.webpage
        self.session = '000000000000'
        socket.setdefaulttimeout(20.0)

        self.cookie = cookielib.CookieJar()
        self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookie))
        self.keepAliveOpener = urllib2.build_opener(keepalive.HTTPHandler())        
        
        if self.config.proxy:
            proxyHandler = urllib2.ProxyHandler({"http":"http://"+self.config.proxy})
            self.opener.add_handler(proxyHandler)
            self.keepAliveOpener.add_handler(proxyHandler)

        headers = [('User-agent', self.config.userAgent), ('Keep-Alive', "300"), ('Accept-Encoding', "gzip,deflate")]
        self.opener.addheaders = headers
        self.keepAliveOpener.addheaders = headers
        self.serverLanguage = config.language
        #print 'self.serverLanguage', self.serverLanguage
                
    def generateRegexps(self, translations):

        if translations:
            reportTmp  = r'<input type="checkbox" name="delmes[0-9]+.*?</th>.*?<th>(?P<date>[0-9].*?)</th>.*?<a href.*?>(?P<coords>\[[0-9:]+\]).*?</a>(?P<planetName>[^<]*?)</span>'
            reportTmp += r'.*?<tr><td>.*?</td><td>(?P<metal>[-0-9.]+)</td>\n'
            reportTmp += r'<td>.*?</td><td>(?P<crystal>[-0-9.]+)</td></tr>\n'
            reportTmp += r'<tr><td>.*?</td><td>(?P<deuterium>[-0-9.]+)</td>\n'
            reportTmp += r'<td>.*?</td><td>(?P<energy>[-0-9.]+)</td></tr>'
            reportTmp2 = r'<table width=[0-9]+><tr><td class=c colspan=4>%s(.*?)</table>'
            self.REGEXP_COORDS_STR  = r"([1-9]{1,3}):([0-9]{1,3}):([0-9]{1,2})"
            self.REGEXP_SESSION_STR = r"[0-9a-zA-Z]{12}"
            self.REGEXPS = \
            {
                'logincheck': re.compile(r'<!-- GFAnalytics -->.*?src="(?P<url1>.*?)".*?<img.*?src="(?P<url2>.*?)"', re.DOTALL |re.I),
                'messages.php': re.compile(r'<input type="checkbox" name="delmes(?P<code>[0-9]+).*?(?=<input type="checkbox")', re.DOTALL |re.I), 
                'fleetSendError':re.compile(r'<span class="error">(?P<error>.*?)</span>', re.I), 
                'myPlanets':re.compile('<option value="/game/index\.php\?page=overview&session='+self.REGEXP_SESSION_STR+'&cp=([0-9]+)&mode=&gid=&messageziel=&re=0" (?:selected)?>(.*?)<.*?\['+self.REGEXP_COORDS_STR+'].*?</option>', re.I), 
                'report': 
                {
                    'all'  :    re.compile(reportTmp, re.DOTALL|re.LOCALE|re.I), 
                    'fleet':    re.compile(reportTmp2 % translations['fleets'], re.DOTALL|re.I), 
                    'defense':  re.compile(reportTmp2 % translations['defense'], re.DOTALL|re.I), 
                    'buildings':re.compile(reportTmp2 % translations['buildings'], re.DOTALL|re.I), 
                    'research': re.compile(reportTmp2 % translations['research'], re.DOTALL|re.I), 
                    'details':  re.compile(r"<td>(?P<type>.*?)</td><td>(?P<cuantity>[-0-9.]+)</td>", re.DOTALL|re.I)
                }, 
                'serverTime':re.compile(r"<th>.*?%s.*?</th>.*?<th.*?>(?P<date>.*?)</th>" %  translations['serverTime'], re.DOTALL|re.I), 
                'availableFleet':re.compile(r'name="maxship(?P<type>[0-9]{3})" value="(?P<cuantity>[-0-9.]+)"', re.I), 
                'maxSlots':re.compile(r"%s\s*([0-9]+).*?([0-9]+)" %  translations['maxFleets'], re.I),
                'researchLevels':re.compile(r">(?P<techName>[^<]+)</a></a>\s*\(.*?(?P<level>\d+)\s*\)", re.I|re.LOCALE),
                'fleetSendResult':re.compile(r"<tr.*?>\s*<th.*?>(?P<name>.*?)</th>\s*<th.*?>(?P<value>.*?)</th>", re.I), 
                'charset':re.compile(r'content="text/html; charset=(.*?)"', re.I),
                # number, name, ownerStatus, owner, alliance
                'solarSystem':re.compile(r'<tr>.*?<a href="#"  tabindex="\d+" >(\d+)</a>.*?<th width="130".*?>[\s]*(?:<a.*?>)?[\s]*([^&<]+).*?<th width="150">.*?<span class="(\w+?)">(.*?)</span>.*?<th width="80">.*?">[\s]*([\w .]*?) *<.*?</tr>'),
                'stats': re.compile(r"<th>(?:<font color='87CEEB'>)?([^<]+)(?:</font>)?</th>.*?<th>([0-9.]+)</th>",re.DOTALL),
                'resources':re.compile(r'<td align="center" class=\'header\' width="90"><font .*?>([-0-9.]+)</font></td>',re.I),
                'missions':re.compile(r'<th>[0-9]+</th>.*?<a title=".*?">([^<]+)</a>.*?<th> <a title="([^"]+)">[0-9]+</a></th>.*?<a href="index.php\?page=galaxy.*?>\[([0-9:]+)\]</a></th>.*?<th>([a-zA-Z]{3} [a-zA-Z]{3} [0-9]+ [:0-9]+)</th>.*?<th><a href="index.php\?page=galaxy.*?>\[([0-9:]+)\]</a>.*?<th>([a-zA-Z]{3} [a-zA-Z]{3} [0-9]+ [:0-9]+)</th>', re.DOTALL|re.I),
                'techtree':re.compile(r'<table width="100%" border=0 cellspacing=0 cellpadding=0><tr><td align=left>.*?session=(?P<session>[0-9a-zA-Z]{12}).*?gid=(?P<id>\d+)">(?P<namd>.*?)</a>', re.DOTALL |re.I)
            }
        else:
            self.REGEXP_SESSION_STR = r"[0-9a-zA-Z]{12}"
            self.REGEXPS = \
            {
                'logincheck': re.compile(r'<!-- GFAnalytics -->.*?src="(?P<url1>.*?)".*?<img.*?src="(?P<url2>.*?)"', re.DOTALL |re.I),
                'techtree':re.compile(r'<table width="100%" border=0 cellspacing=0 cellpadding=0><tr><td align=left>.*?session=(?P<session>[0-9a-zA-Z]{12}).*?gid=(?P<id>\d+)">(?P<namd>.*?)</a>', re.DOTALL |re.I)
            } 
		    
    def setSession(self, value):
        self._session = value
        self.saveState()
        
    def getSession(self): 
        return self._session
    session = property(getSession, setSession)    
    
    def serverTime(self):
        return self.serverTimeDelta + datetime.now()
            
    def _fetchPhp(self, php, **params):
        params['session'] = self.session
        url = "http://%s/game/%s?%s" % (self.webpage, php, urllib.urlencode(params))
        return self._fetchValidResponse(url)
    
    def _fetchForm(self, form):
        return self._fetchValidResponse(form.click())
    
    def _fetchValidResponse(self, request, skipValidityCheck = False, changeLastUrl = True):
        self.currentTime  = 0
        self._mutex.acquire()

        if isinstance(request, str):
            request = urllib2.Request(request)
        if self.lastFetchedUrl:
            request.add_header('Referer',self.lastFetchedUrl)
            
            
        valid = False            
        while not valid:
            self.currentTime = self.currentTime + 1
            if self.currentTime > 4:
                BotFatalError("Maybe in dead loop now!!")
                break
            
            valid = True
            try:
                response = self.opener.open(request) 
                tmpUrl = response.geturl()
                if __debug__: 
                    print >>sys.stderr, "         Fetched " + tmpUrl
                    
                if changeLastUrl:    
                    self.lastFetchedUrl = tmpUrl
                cachedResponse = StringIO()
                if response.info().has_key('Content-Encoding') and 'gzip' in response.info()['Content-Encoding'] :
                    zbuf = StringIO(response.read())
                    cachedResponse = StringIO(gzip.GzipFile(fileobj=zbuf,mode='rb').read())
                else :
                    cachedResponse = StringIO(response.read())
                p = cachedResponse.getvalue()
                cachedResponse.seek(0)
                
                if skipValidityCheck:
                    break               
                elif not p or 'errorcode=8' in self.lastFetchedUrl:
                    valid = False
                elif self.translations['dbProblem'] in p or self.translations['untilNextTime'] in p or "Grund 5" in p:
                    valid = False
                    print 'Raise BotReset Error'
                    raise BotReset()
                elif 'errorcode=2' in self.lastFetchedUrl:
                    raise BotFatalError("Invalid username and/or password.")
            except urllib2.HTTPError, e:
                if e.code == 302: # happens once in a while when user and bot are playing simultaneusly.
                    raise BotError()
                else: raise e
            except (urllib2.URLError, httplib.IncompleteRead, httplib.BadStatusLine), e:
                self._eventMgr.connectionError(e)
                valid = False
            except Exception, e:
                if "timed out" in str(e):
                    self._eventMgr.connectionError("timed out")
                    valid = False
                else: raise e
            if not valid: 
                mySleep(5)
         
        #print 'cookie', str(self.cookie)
        cookie = re.findall(r"<Cookie\s([^ ]*)", str(self.cookie))
        self.gui.setCookie(cookie)     
        self._mutex.release()
        return cachedResponse
    
    def doLogin(self):
        if self.serverTimeDelta and self.serverTime().hour == 3 and self.serverTime().minute == 0: 
            mySleep(60)

        allTranslations = Translations()
        #First init translations from tranlate file
        try:
	     self.translations = allTranslations[self.serverLanguage]
        #First int re
        except KeyError:
            raise BotFatalError("Server language (%s) not supported by bot" % self.serverLanguage)
        self.generateRegexps(translations=None)
            
        self.server = "http://"+self.webpage+"/game/reg/login2.php?"+"v=2"+"&login="+self.config.username+"&pass="+self.config.password
        #print self.server
        page = self._fetchValidResponse(self.server, True).read()
        
        try:
            self.session = re.findall(self.REGEXP_SESSION_STR, page)[0]
        except IndexError:
           raise BotFatalError(page)
        #print self.session

        page = self._fetchPhp('index.php', page='overview', lgn=1).read()
        url1, url2 = self.REGEXPS['logincheck'].findall(page)[0]
        #print url1
        #print url2
        #somehow they are checking this!
        self._fetchValidResponse(url1, skipValidityCheck = True, changeLastUrl = False)
        self._fetchValidResponse(url2, skipValidityCheck = True, changeLastUrl = False)

        #now from techtree to get auto trans for building/research/ship/defense name
        page = self._fetchPhp('index.php', page='techtree').read()
        
        for session,gid,local_name in self.REGEXPS['techtree'].findall(page):
            self.translations[INGAME_TYPES_BY_CODE[int(gid)].name] = local_name
            
        self.gui.translations = self.translations
        self.translationsByLocalText = dict([ (value, key) for key, value in self.translations.items() ])
        self.generateRegexps(self.translations)
 
        self._eventMgr.loggedIn(self.config.username, self.session)
        mySleep(5)          
        self.saveState()

    def getMyPlanets(self):
        page = self._fetchPhp('index.php', page='overview').read()
        myPlanets = []
        for code, name, galaxy, ss, pos in self.REGEXPS['myPlanets'].findall(page):
            coords = Coords(galaxy, ss, pos)
            for planet in myPlanets:
                if planet.coords == coords: # we found a moon for this planet
                    coords.coordsType = Coords.Types.moon
            planet = OwnPlanet(coords, name.strip(), code)
            #print 'MyPlanets:', planet
            myPlanets.append(planet)
        
        if myPlanets:
            strTime = self.REGEXPS['serverTime'].findall(page)[0]
            serverTime = parseTime(strTime)
            self.serverTimeDelta = serverTime - datetime.now()
            self.serverCharset = self.REGEXPS['charset'].findall(page)[0]
            self.myPlanets = myPlanets
        else:
            BotFatalError("No Planets are found in page overview")
        return myPlanets
    
    def readMessagePage(self):
        page = self._fetchPhp('index.php', page='messages',dsp='1')
        return page
        
    def getEspionageReports(self):
        page = self._fetchPhp('index.php', page='messages',dsp='1').read()
        #print page
        
        rawMessages = {}
        for match in self.REGEXPS['messages.php'].finditer(page):
            rawMessages[match.group('code')] = match.group(0)
            
        reports = []              
        for code, rawMessage in rawMessages.items():
            if 'class="espionagereport"' not in rawMessage:
                #Some other messages
                #print 'espionagereport not in rawMessage'
                continue

            #print rawMessage
            m = self.REGEXPS['report']['all'].search(rawMessage)
            if m == None: #theorically should never happen
                warnings.warn("Error parsing espionage report.")
                continue
            planetName = m.group('planetName')
            coords = Coords(m.group('coords'))
            date = parseTime(m.group('date'), "%m-%d %H:%M:%S")
            #print planetName
            #print coords
            #print date
            
            resources = Resources(m.group('metal').replace('.', ''), m.group('crystal').replace('.', ''), m.group('deuterium').replace('.', ''))

            report = EspionageReport(coords, planetName, date, resources, code)
            
            for i in "fleet", "defense", "buildings", "research":
                dict = None
                match = self.REGEXPS['report'][i].search(rawMessage)
                if match:
                    dict, text = {}, match.group(1)
                    for fullName, cuantity in self.REGEXPS['report']['details'].findall(text):
                        try :
                            dict[self.translationsByLocalText[fullName.strip()]] = int(cuantity.replace('.', ''))
                        except KeyError, e1 :
                            raise BotError("Unknown espionnage report string, check your translation file : %s", e1)

                setattr(report, i, dict)
                
            report.rawHtml = rawMessage
            reports.append(report)
            
        return reports
        
    def buildBuildings(self, building, planet):
        self._fetchPhp('index.php', page='b_building', bau=building.code, cp=planet.code)
        
    def launchMission(self, mission, abortIfNotEnough = True, slotsToReserve = 0):
        while True:
            # assure cuantities are integers
            for shipType, cuantity in mission.fleet.items():
                mission.fleet[shipType] = int(cuantity)
                        
            # 1st step: select fleet
            page = self._fetchPhp('index.php', page='flotten1', mode='Flotte', cp=mission.sourcePlanet.code)
            pageText = page.read()
            page.seek(0)
            
            resource = self.getMyCurrentPlanetResources(pageText)
            self.updateMyPlanetsResources(resource, mission.sourcePlanet)
            #print 'In launchMisson,resource=',resource
            mySleep(1);

            #print 'self.getFreeSlots(pageText)', self.getFreeSlots(pageText)
            #print 'int(slotsToReserve)', int(slotsToReserve)
            if self.getFreeSlots(pageText) <= int(slotsToReserve):
                #print 'Now raise NoFreeSlotsError in launchMission'
                print 'Raise NoFreeSlotsError in line 399'
                raise NoFreeSlotsError(self.getFlyingMissions(pageText))
                break

            availableFleet = self.getAvailableFleet(None, pageText)
            form = ParseFile(page, self.lastFetchedUrl, backwards_compat=False)[-1]
            
            for shipType, requested in mission.fleet.items():
                available = availableFleet.get(shipType, 0)
                if available == 0 or (abortIfNotEnough and available  < requested):
                    raise NotEnoughShipsError(availableFleet, {shipType:requested},self.getFlyingMissions(pageText), available)
                    break
                    
                shipCode = 'ship'+str(INGAME_TYPES_BY_NAME[shipType].code)
                form[shipCode] = str(requested)

            # calculate mission consumption to check if there is enough deut on the planet
            mission.consumption = 0
            maxspeed = 9999999999
            distance = mission.sourcePlanet.coords.distanceTo(mission.targetPlanet.coords)
            for shipType, requested in mission.fleet.items() :
                if INGAME_TYPES_BY_NAME[shipType].speed < maxspeed:
                    maxspeed = INGAME_TYPES_BY_NAME[shipType].speed

            flightTime = mission.sourcePlanet.coords.flightTimeTo(mission.targetPlanet.coords, maxspeed, mission.speedPercentage)
            for shipType, requested in mission.fleet.items() :
                basicConsumption = INGAME_TYPES_BY_NAME[shipType].consumption * requested
                #print 'self.config.gameSpeed', self.config.gameSpeed
                spd = 35000.0 / (flightTime.seconds*int(self.config.gameSpeed) - 10) * math.sqrt(distance * 10.0 / float(INGAME_TYPES_BY_NAME[shipType].speed))
                mission.consumption += (basicConsumption *distance/35000.0* ((spd / 10.0) + 1) * ((spd / 10.0) + 1))
            mission.consumption = round(mission.consumption+1)

            #print 'Now use getMyCurrentPlanetResources!'
            resources = self.getMyCurrentPlanetResources(pageText)
            
            #print "Consumption : Needed : " + str(consumption) +" Available : " + str(resources[2])
            if mission.consumption > resources[2] :
                raise NotEnoughDeutError(mission.consumption, resources[2])
                break
            
            # 2nd step: select destination and speed
            page = self._fetchForm(form)
            forms = ParseFile(page, self.lastFetchedUrl, backwards_compat=False)
            if not forms or 'flotten3' not in forms[0].action:
                continue
            form = forms[0]
            destCoords = mission.targetPlanet.coords
            form['galaxy']    = str(destCoords.galaxy)
            form['system']    = str(destCoords.solarSystem)
            form['planet']    = str(destCoords.planet)
            form['planettype']= [str(destCoords.coordsType)]
            form['speed']      = [str(mission.speedPercentage / 10)]
            # 3rd step:  select mission and resources to carry
            page = self._fetchForm(form)
            form = None
            pf = ParseFile(page, self.lastFetchedUrl, backwards_compat=False)
            if len(pf) != 0 :
                form = pf[0]
            else :
                continue
            try:
                form['order']      = [str(mission.missionType)]
            except ControlNotFoundError:
                continue
            except:
                continue
            
            resources = mission.resources
            form['resource1'] = str(resources.metal)
            form['resource2'] = str(resources.crystal)
            form['resource3'] = str(resources.deuterium)
            # 4th and final step: check result
            page = self._fetchForm(form).read()

            if self.translations['fleetCouldNotBeSent'] in page:
                continue
            
            errors = self.REGEXPS['fleetSendError'].findall(page)
            if len(errors) > 0 or 'class="success"' not in page:
                errors = str(errors)
                if   self.translations['fleetLimitReached'] in errors:
                    print 'Raise NoFreeSlotsError in line 458'
                    raise NoFreeSlotsError(self.getFlyingMissions())
                    break
                elif self.translations['noShipSelected'] in errors:
                    raise NotEnoughShipsError(availableFleet, mission.fleet)
                    break
                else:
                    raise FleetSendError(errors)
                    continue
    
            resultPage = {}
            for type, value in self.REGEXPS['fleetSendResult'].findall(page):
                resultPage[type] = value
    
            # fill remaining mission fields
            arrivalTime = parseTime(resultPage[self.translations['arrivalTime']])
            returnTime = parseTime(resultPage[self.translations['returnTime']])
            mission.flightTime = returnTime - arrivalTime
            mission.launchTime = arrivalTime - mission.flightTime
            mission.distance =  int(resultPage[self.translations['distance']].replace('.', ''))
            mission.consumption = int(resultPage[self.translations['consumption']].replace('.', ''))
            sentFleet = {}
            for fullName, value in resultPage.items():
                name = self.translationsByLocalText.get(fullName)
                if name is None:
                    continue
                if name in INGAME_TYPES_BY_NAME.keys():
                    sentFleet[name] = int(value.replace('.', ''))
    
            if mission.fleet != sentFleet:
                warnings.warn("Not all requested fleet was sent. Requested: %s. Sent: %s" % (mission.fleet, sentFleet))
                mission.fleet = sentFleet
            mySleep(1);
            page = self._fetchPhp('index.php', page='flotten1', mode='Flotte', cp=mission.sourcePlanet.code)
            break

    def getFreeSlots(self, alreadyFetchedPage = None):
        page = alreadyFetchedPage
        if not page:
            page = self._fetchPhp('index.php', page='flotten1', mode='Flotte').read()
        slots = []
        slots = self.REGEXPS['maxSlots'].findall(page)
        
        if slots:
            slotsF, slotsM = slots[0]
            maxFleets = int(slotsM)
            usedSlots = int(slotsF)
            print 'usedSlots,maxFleets',usedSlots, maxFleets
            return maxFleets - usedSlots
        else:
            BotFatalError("Can not get slots info on page")
            return 0
        

    def getFlyingMissions(self,alreadyFetchedPage = None) :
        page = alreadyFetchedPage
        if not page:
            page = self._fetchPhp('index.php', page='flotten1', mode='Flotte').read()
        missions = []
        
        #print 'missions', self.REGEXPS['missions'].findall(page)
        for mission in self.REGEXPS['missions'].findall(page) :
            try:
                missionType = self.translationsByLocalText[mission[0]]
            except KeyError, e1:
                raise BotError("Unknown Fleet order, check your translation file : %s", e1)

            if missionType == 'attack' :
                missionType = Mission.Types.attack
            elif missionType == 'attackgroup' :
                missionType = Mission.Types.attackgroup
            elif  missionType == 'transport' :
                missionType = Mission.Types.transport
            elif  missionType == 'deploy' :
                missionType = Mission.Types.deploy
            elif missionType == 'deployally' :
                missionType == Mission.Types.deployally
            elif  missionType == 'spy' :
                missionType = Mission.Types.spy
            elif  missionType == 'recycle' :
                missionType = Mission.Types.recycle
            elif  missionType == 'destroy' :
                missionType = Mission.Types.destroy
            elif missionType == 'expedition':
                missionType = Mission.Types.expedition
            else:
                missionType = Mission.Types.unknown

            source = Planet(Coords(mission[2]))
            destination = Planet(Coords(mission[4]))
            
            fleet = {}
            for ship in mission[1].split('\n') :
                if ship != '' :
                    shiptype, quantity = ship.split(':')
                    try :
                        fleet[self.translationsByLocalText[shiptype]] = int(quantity)
                    except KeyError, e1 :
                        raise BotError("Unknown ship name, check your translation file : %s", e1)

            
            m = Mission(missionType, source, destination, fleet)
            
            maxspeed = 9999999999
            for shipType, requested in m.fleet.items() :
                if INGAME_TYPES_BY_NAME[shipType].speed < maxspeed:
                    maxspeed = INGAME_TYPES_BY_NAME[shipType].speed
            
            m.launchTime = parseTime(mission[3])
            #m.flightTime = parseTime(mission[5]) - m.launchTime
            m.flightTime = source.coords.flightTimeTo(destination.coords, maxspeed)
            #print 'm.launchTime', m.launchTime
            #print 'm.flightTime', m.flightTime
            missions.append(m)
        return missions

    def getTimeForFreeSlot(self, alreadyFetchedPage = None):
        page = alreadyFetchedPage
        if not page:
            page = self._fetchPhp('index.php', page='flotten1', mode='Flotte').read()
        times = re.findall(r"<th>([a-zA-Z]{3} [a-zA-Z]{3} [0-9]+ [:0-9]+)</th>", page)
        time = None
        if len(times)==0:
            time = None
        else:
            time = parseTime(times[1])
        return time
    
    def getAvailableFleet(self, planet, alreadyFetchedPage = None):    
        page = alreadyFetchedPage
        if not page:
            page = self._fetchPhp('index.php', page='flotten1', mode='Flotte', cp=planet.code).read()
        fleet = {}
        for code, cuantity in self.REGEXPS['availableFleet'].findall(page):
            fleet[INGAME_TYPES_BY_CODE[int(code)].name] = int(cuantity.replace('.', ''))
        return fleet

    def deleteMessages(self, messages):
        page = self._fetchPhp('index.php', page='messages')
        form = ParseFile(page, self.lastFetchedUrl, backwards_compat=False)[0]
        for message in messages:
            checkBoxName = "delmes" + message.code
            try:
                form[checkBoxName]      = [None] # actually this marks the checbox as checked (!!)
                form["deletemessages"] = ["deletemarked"]
            except ControlNotFoundError:
                if __debug__:
                    print >> sys.stderr, "Could not delete message " + str(message)
            
        self._fetchForm(form)
        
    def updateMyPlanetsResources(self, resource,planet):
        if len(resource) < 3:
            print 'Error when get resource'
            return 
    
        resources = self.myPlanetsResources
        inc = 5
        for p in xrange(len(resources)/inc):
            if str(resources[inc*p]).find(str(planet.coords)) != -1:
                #print 'Find planet to p,update', p, planet
                resources[inc*p+1] = resource[0]
                resources[inc*p+2] = resource[1]
                resources[inc*p+3] = resource[2]
                resources[inc*p+4] = 'updated'
                break
                
        self.myPlanetsResources = resources
        self.gui.myPlanetsResTableUpdate(self.myPlanetsResources)
        
    def resetMyPlanetsResFlag(self):
        resources = self.myPlanetsResources
        inc = 5
        for p in xrange(len(resources)/inc):
            resources[inc*p+4] = 'no'
                
        self.myPlanetsResources = resources

    def getAndUpdateMyPlanetsResources(self):
    
        if not self.myPlanetsResources:
            for planet in self.myPlanets:
                self.myPlanetsResources.append(str(planet))
                self.myPlanetsResources.append(0)
                self.myPlanetsResources.append(0)
                self.myPlanetsResources.append(0)
                self.myPlanetsResources.append('no')
            
        resources = self.myPlanetsResources
        inc = 5
        for p in xrange(len(resources)/inc):
            if resources[inc*p+4] == 'no':
                for planet in self.myPlanets:
                    if str(resources[inc*p]).find(str(planet.coords)) != -1:
                        page = self.goToPlanet(planet)
                        new_resources = self.getMyCurrentPlanetResources(page)
                        resources[inc*p+1] = new_resources[0]
                        resources[inc*p+2] = new_resources[1]
                        resources[inc*p+3] = new_resources[2]
            else:
                resources[inc*p+4] = 'no'
            mySleep(1)
                
        self.myPlanetsResources = resources
        self.gui.myPlanetsResTableUpdate(self.myPlanetsResources)


    def getMyCurrentPlanetResources(self, webpage):
        resources = []
        resources = self.REGEXPS['resources'].findall(webpage)
        i = 0
        for i in xrange(len(resources)) :
            resources[i] = int(resources[i].replace('.',''))
            
        return resources
            
    def getResearchLevels(self):
        for planet in self.myPlanets:
            page = self._fetchPhp('index.php', page='buildings', mode='Forschung',cp=planet.code).read()
            page = page.replace("\n", "")
            #print page
            
            levels = {}
            #tmp = self.REGEXPS['researchLevels'].findall(page)
            #print 'tmp', tmp
            for fullName, level in self.REGEXPS['researchLevels'].findall(page):
                try :
                    levels[self.translationsByLocalText[fullName]] = int(level)
                except KeyError, e1 :
                    raise BotError("Unknown research name, check your translation file : %s", e1)

            #print levels
            if 'impulseDrive' in levels or 'combustionDrive' in levels:
                return levels
        raise BotFatalError("Not enough technologies researched to run the bot")
                
    def goToPlanet(self, planet):
        page = self._fetchPhp('index.php', page='overview', cp=planet.code).read()
        return page
  
    def selectDeuteriumSourcePlanet(self):
        find = False
        for planet in self.myPlanets:
            page = self.goToPlanet(planet)
            resources = self.REGEXPS['resources'].findall(page)
            if int(str(resources[2]).replace('.', ''))> 200:
                print 'Source planet selected:', planet
                find = True
                break
        if find == False:
            raise BotFatalError("Probably there is not enough deuterium on all planets.")
            
    def getSolarSystems(self, solarSystems): # solarsytems is an iterable of tuples

        found = []
        print solarSystems
        for searchGalaxy, searchSolarSystem in solarSystems:
            #print 'in getSolarSystems', galaxy, solarSystem
            params = {'no_header':'1', 'session':self.session, 'galaxy':searchGalaxy, 'system':searchSolarSystem}
            url = "http://%s/game/index.php?page=galaxy&%s" % (self.webpage, urllib.urlencode(params))
            if __debug__: 
                print >>sys.stderr, "         Fetched " + url
            
            try:
                response = self.opener.open(url)
                if 'error' in  response.geturl():
                    continue
            except:
                continue
            
            page = None
            try:
                if response.info().has_key('Content-Encoding') and 'gzip' in response.info()['Content-Encoding'] :
                    zbuf = StringIO(response.read())
                    page = gzip.GzipFile(fileobj=zbuf,mode='rb').read()
                else :
                    page = response.read()
            except:
                continue

            page = page.replace("\n", "")
            #print 'where', str(page).find(str(self.translations['noDeuterium'])) 
            
            if str(page).find(str('<span class="error">')) != -1 and str(page).find(str(self.translations['noDeuterium'])) != -1:
                #print 'error message',self.translations['noDeuterium']
                raise BotFatalError("Probably there is not enough deuterium planet.")
            else:
                galaxy      = re.findall('input type="text" name="galaxy" value="(\d+)"', page)[0]
                solarSystem = re.findall('input type="text" name="system" value="(\d+)"', page)[0]
                        
                foundPlanets = []
                for number, name, ownerStatus, owner, alliance in self.REGEXPS['solarSystem'].findall(page):
                # Absolutely ALL EnemyPlanet objects of the bot are created here
                    if len(owner) != 0 :
                        planet = EnemyPlanet(Coords(galaxy, solarSystem, number), owner, ownerStatus, name, alliance)
                        foundPlanets.append(planet)
            
            if foundPlanets:
                found.append((searchGalaxy, searchSolarSystem,foundPlanets))
            #print 'foundPlanets', foundPlanets
        
        return found
        
    def getStats(self, type): # type can be: pts for points, flt for fleets or res for research
        page = self._fetchPhp('index.php', page='stat', start=1)
        form = ParseFile(page, self.lastFetchedUrl, backwards_compat=False)[-1]
        
        for i in range(1, 1401, 100):
            form['type'] = [type]
            form['start'] = [str(i)]
            page = self._fetchForm(form).read()
            for player, points in self.REGEXPS['stats'].findall(page):
                yield player, int(points.replace('.', ''))
            
    def saveState(self):
        file = open(FILE_PATHS['webstate'], 'wb')
        pickler = cPickle.Pickler(file, 2)
        pickler.dump(self.webpage)
        pickler.dump(self.session)
        file.close()
        
    def loadState(self):
        try:
            file = open(FILE_PATHS['webstate'], 'rb')
            u = cPickle.Unpickler(file)            
            self.webpage = u.load()            
            self.session = u.load()
            file.close()
        except (EOFError, IOError):
            try:
                os.remove(FILE_PATHS['webstate'])              
            except Exception : pass
            return False
        return True   
    
def parseTime(strTime, format = "%a %b %d %H:%M:%S"):# example: Mon Aug 7 21:08:52                        
    ''' parses a time string formatted in OGame's most usual format and 
    converts it to a datetime object'''
    
    format = "%Y " + format
    strTime = str(datetime.now().year) + " " +strTime
    tuple = strptime(strTime, format) 
    return datetime(*tuple[0:6])
